package com.shenmazong.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shenmazong.utils.ResultResponse;
import com.shenmazong.utils.TokenUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * @author 军哥
 * @version 1.0
 * @description: TODO
 * @date 2022/1/6 15:56
 */

@Configuration
@Slf4j
public class GatewayFilter implements GlobalFilter, Ordered {

    @Autowired
    RedisTemplate redisTemplate;

    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 检查url：白名单
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();
        String url = request.getURI().getRawPath();
        log.info("url:"+url);
        if(url.contains("/userLogin")) {
            return chain.filter(exchange);
        }
        if(url.contains("/addUser")) {
            return chain.filter(exchange);
        }
        if(url.contains("/sendCode")) {
            return chain.filter(exchange);
        }
        if(url.contains("/img/")) {
            return chain.filter(exchange);
        }

        // 检查token
        String token = request.getHeaders().getFirst("token");
        if(token == null) {
            log.info("没有携带token");
            return tokenErrror(response, 403);
        }

        // 解析token
        TokenUtils tokenUtils = TokenUtils.token().setKey("123456");
        int res = tokenUtils.parseToken(token);
        if(TokenUtils.ERROR_SIGN == res || TokenUtils.ERROR == res) {
            log.info("解析token 401");
            return tokenErrror(response, 401);
        }

        String userId = tokenUtils.getClaim("userId");
        String userName = tokenUtils.getClaim("userName");

        // 买家、卖家、管理员
        // 和reidis中的token进行比较
        String key = "pc:"+userId;
        Boolean ok = false;
        if(redisTemplate.hasKey("pc:"+userId)) {
            ok = true;
        }
        else if(redisTemplate.hasKey("admin:"+userId)) {
            ok = true;
        }
        else if(redisTemplate.hasKey("seller:"+userId)) {
            ok = true;
        }
        if(!ok) {
            log.info("和reidis中的token进行比较 401");
            return tokenErrror(response, 401);
        }


        // token刷新
        String newToken = TokenUtils.token()
                .setKey("123456")
                .setExpire(60 * 30)
                .setClaim("userId", userId)
                .setClaim("userName", userName)
                .createToken();

        redisTemplate.opsForValue().set(key, newToken, 30, TimeUnit.MINUTES);

        // 设置响应头
        response.getHeaders().set("token", newToken);

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private Mono<Void> tokenErrror(ServerHttpResponse response, int code) throws JsonProcessingException {
        // 解决乱码
        HttpHeaders headers = response.getHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 添加错误信息
        ResultResponse resultResponse = ResultResponse.FAILED(code, "token错误");

        ObjectMapper objectMapper = new ObjectMapper();
        String err = objectMapper.writeValueAsString(resultResponse);

        DataBuffer wrap = response.bufferFactory().wrap(err.getBytes(StandardCharsets.UTF_8));

        // 返回错误信息
        return response.writeWith(Mono.just(wrap));
    }
}
